using System;
using System.Collections.Generic;

namespace TALoaders
{
    public enum Loader
    {
        Test,
        Yahoo,
        Google,
        OandaFX,
        Bloomberg
    }

    /// <summary>Abstrace base class for all loaders. Defines all downloader's interface</summary>
    public abstract class BaseLoader
    {
        #region Private members
        private Loader loaderM;
        #endregion

        #region Public Interface
        public BaseLoader(Loader loader)
        {
            loaderM = loader;
        }

        public abstract SortedList<DateTime, Quote> getHistoricalPrices(string ticker, DateTime startDate, DateTime endDate);
        
        public abstract double getLastPrice(string ticker, out string timeStamp);

        /// <summary>Get single time-series of dated historical prices (based on QuoteType)</summary>
        /// <param name="ticker">Security ticker</param>
        /// <param name="startDate">historical prices start date</param>
        /// <param name="endDate">historical prices end date</param>
        /// <param name="type">quoteType e.g. Close</param>
        /// <returns>Dated time series of QuoteType values</returns>
        virtual public SortedList<DateTime, double> getHistoricalPrices(string ticker, DateTime startDate, DateTime endDate, QuoteType type)
        {
            SortedList<DateTime, Quote> quotes = this.getHistoricalPrices(ticker, startDate, endDate);
            int nOfRows = quotes.Count;
            SortedList<DateTime, double> result = new SortedList<DateTime, double>(nOfRows);
            foreach (KeyValuePair<DateTime, Quote> dateQuotePair in quotes)
            {
                DateTime date = dateQuotePair.Key;
                double value = dateQuotePair.Value.getValue(type);
                result.Add(date, value);
            }
            return result;
        }

        public Loader Loader
        {
            get { return this.loaderM; }
        }
        #endregion
    }

    public class DownloaderFactory
    {
        static private Dictionary<string, BaseLoader> loadersM = new Dictionary<string, BaseLoader>();

        public static BaseLoader createCachedDownloader(string loaderName)
        {
            BaseLoader resultLoader;

            if (loadersM.TryGetValue(loaderName, out resultLoader))
                // the loader alredy exists. Reuse it!
                return resultLoader;

            // this loader type has not been created so far.
            // Create new one!
            Loader loader = (Loader)Enum.Parse(typeof(Loader), loaderName);
            switch (loader)
            {
                case Loader.Test:
                    resultLoader = new CachedDownloader(new TestDownloader());
                    break;
                case Loader.Yahoo:
                    resultLoader = new CachedDownloader(new YahooDownloader());
                    break;
                case Loader.Google:
                    resultLoader = new CachedDownloader(new GoogleDownloader());
                    break;
                case Loader.OandaFX:
                    resultLoader = new CachedDownloader(new OandaFXLoader());
                    break;
                case Loader.Bloomberg:
                    resultLoader = new CachedDownloader(new BloombergLoader());
                    break;
                default:
                    throw new Exception("Unknown downloader: " + loaderName);
            }

            loadersM.Add(loaderName, resultLoader);
            return resultLoader;
        }

        /// <summary>Return array of default tickers recognized by the loader</summary>
        /// <param name="loaderName">String loader name</param>
        /// <returns>Array of tickers</returns>
        public static string[] getDefaultTickers(string loaderName)
        {
            string[] tickers;
            Loader loader = (Loader)Enum.Parse(typeof(Loader), loaderName);
            switch (loader)
            {
                case Loader.Test:
                case Loader.Yahoo:
                    tickers = new string[] { "^OMX", "^STOXX50E", "^GDAXI", "^DJI", "^FTSE", "^N225", 
                    "^HSI", "^VIX", "^GOX", "^RUA" /* Russell 3000 */ };
                    break;
                case Loader.Google:
                    tickers = new string[] { "GLD" /* Gold */ , "SLV" /* Silver */ , "PPLT" /* Platinum */
                        , "JJC" /* Copper */, "OIL" /* Crude Oil */, "UNG" /* Natural gas */
                        , "LON:CORN" /* Corn */, "SGG" /* Sugar */, "LON:WEAT" /* Wheat */ };
                    break;
                case Loader.OandaFX:
                    tickers = new string[] { "EURUSD", "AUDUSD", "EURSEK", "USDSEK", "GBPSEK", "CHFSEK", "SEKCZK" };
                    break;
                case Loader.Bloomberg:
                    tickers = new string[] { "OMX Index", "SX5E Index" /* EuroStoxx50 */, "RX1 Comdty", "TY1 Comdty", "EURUSD Curncy", "AUDUSD Curncy", 
                    "GOLDS Comdty" /* Gold */ , "SB1 Comdty" /* Sugar */, "CO1 Comdty" /* Brent Oil */, "W 1 Comdty" /* Wheat Future CBOT*/,
                    "C 1 Comdty" /* Corn Future */};
                    break;
                default:
                    throw new Exception("Unsupported loader " + loaderName);
            }

            return tickers;
        }
    }
}
